var StockTracker = (function(){
  var entryCount = 0;
  var stockSymbols = new Array;
  
  function _init(){    
  }
  
  function _checkForStock(value){
    for (var i = 0; i < stockSymbols.length; i++) {
      if (stockSymbols[i] == value) 
        return true;
    }
    return false;
  }
  
  function _getStockIndexNumber(symbol){
    for (var i = 0; i < stockSymbols.length; i++) {
      if (stockSymbols[i] == symbol) {
        return i;
      }
    }
    return undefined;
  }
  
  /**
   * Called to start the request out to YQL for stock data.
   * 
   * @param {String} symbol - The stock symbol
   * @param {Boolean} update - Is this call an update for a stock already displayed
   * @param {Boolean} isReload - Is this a call for a stock that was loaded from the prefrences
   */
  function _getData(symbol, update, isReload){
    var requestURL = null;
    
    //Hide the error message
    mwl.switchClass('#incorrect_symbol_message', 'show', 'dont_show');
    
    if (symbol == null) {
      symbol = document.getElementById('symbol').value;
    }

    if (symbol != null && symbol != undefined) {
      requestURL = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20%3D%20'" + symbol + "'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
      _AjaxWrapper(requestURL, isReload);
    }
  }
  
  function _loadStocksFromPrefs(){
    for (var i = 0; i < stockSymbols.length; i++) {
      _getData(stockSymbols[i], false, true);
    }
  }
  
  function _AjaxWrapper(requestURL,isReload){
    var request = new XMLHttpRequest();
    
    this.processResponse = function(){
      if (request.readyState == 4 && request.status == 200) {
      
        /* 
         * Due to the version of Rhino running in the proxy the native JSON object is not available so
         * we can't just do JSON.parse(responseText). We are forced to do an eval in order to turn the JSON response into a JSON object.
         */

        var data = eval('(' + request.responseText + ')');
        
        /*
         * The way this API reacts to bad stock symobls is by returning 'N/A' for the ErrorIndicationreturnedforsymbolchangedinvalid property.
         */
        if (data.query.results.quote.ErrorIndicationreturnedforsymbolchangedinvalid == 'N/A' || data.query.results.quote.ErrorIndicationreturnedforsymbolchangedinvalid == null) {
          var dataToSend = {};
          dataToSend.symbol = data.query.results.quote.Symbol;
          dataToSend.changeAmount = data.query.results.quote.Change;
          dataToSend.currentPrice = data.query.results.quote.LastTradePriceOnly;
          dataToSend.dayHigh = data.query.results.quote.DaysHigh;
          dataToSend.dayLow = data.query.results.quote.DaysLow;
          dataToSend.stockExchange = data.query.results.quote.StockExchange;
          dataToSend.dayHigh = data.query.results.quote.DaysHigh;
          dataToSend.dayLow = data.query.results.quote.DaysLow;
          dataToSend.open = data.query.results.quote.Open;
          dataToSend.prevClose = data.query.results.quote.PreviousClose;
          
          if (isReload) {
            _makePageElement(dataToSend, _getStockIndexNumber(dataToSend.symbol));
          }
          else 
            if (_checkForStock(dataToSend.symbol)) {
              _updatePageElement(dataToSend);
              mwl.switchClass('#stock_entry_' + _getStockIndexNumber(dataToSend.symbol) + '_loader', 'show', 'dont_show');
            }
            else {
              _makePageElement(dataToSend);
            }
			//mwl.toggleClass('#progress_anim', 'progress_visible');		
        }
        else {
          mwl.switchClass('#incorrect_symbol_message', 'dont_show', 'show');
        }
		mwl.toggleClass('#progress_anim', 'progress_visible');
      }	  
    }
    
    request.onreadystatechange = this.processResponse;
    request.open('GET', requestURL, true);
    request.send();
  }
  
  function _setBackgroundImage(changeAmount){
    if (changeAmount.indexOf("-") > -1) {
      return 'stock_item_red';
    }
    else {
      return 'stock_item_green';
    }
  }
  
  /**
   * Actually construct the needed elements to make the stock entry. In this method we are making each element
   * one by one which does add to the overall code size but it makes things easier to find in the code. Also by not constructing 
   * a giant innerHTML string we don't have to worry about escaping quotes and all the headaches that come along with that.
   * 
   * @param {Object} data -  The dataToSend object from the AjaxWrapper
   * @param {Object} stockIndexNumber -  The index of the stock in the stockSymbols array
   */
  function _makePageElement(data, stockIndexNumber){
    mwl.switchClass('#load_from_prefs', 'show', 'dont_show');
    
    var indexNumber = entryCount;
    if(stockIndexNumber) {
      indexNumber = stockIndexNumber;
    }
    
    var stockEntryWrapperDiv = document.createElement('div');
    stockEntryWrapperDiv.setAttribute('id', 'stock_entry_' + indexNumber + '_wrapper');
    stockEntryWrapperDiv.setAttribute('class', _setBackgroundImage(data.changeAmount));
    /*
     * We want to put the stock that the user just searched for at the top of the results panel so they don't have 
     * to scroll in order to see the data that they are looking for.
     */
    if (document.getElementById('data_grid').childNodes.length > 0) {
      document.getElementById('data_grid').insertBefore(stockEntryWrapperDiv, document.getElementById('data_grid').childNodes[0]);
    }
    else {
      document.getElementById('data_grid').appendChild(stockEntryWrapperDiv);
    }
    
    var entryDiv = document.createElement('div');
    entryDiv.setAttribute('id', 'stock_entry_' + indexNumber);
    entryDiv.setAttribute('class', 'stock_item');
    stockEntryWrapperDiv.appendChild(entryDiv);
    
    /*
     * Using a table here to make the layout easier to deal with. While it can be done with div's and CSS I took
     * the easy way out.
     */
    var infoTable = document.createElement('table');
    infoTable.setAttribute('class', 'symbol_info_table');
    entryDiv.appendChild(infoTable);
    
    var infoTableRow1 = document.createElement('tr');
    infoTable.appendChild(infoTableRow1);
    
    var infoTableRow1Col1 = document.createElement('td');
    infoTableRow1Col1.setAttribute('id', 'stock_entry_' + indexNumber + '_symbol');
    infoTableRow1Col1.setAttribute('class', 'symbol_info_table_col');
    infoTableRow1Col1.innerHTML = data.symbol
    infoTableRow1.appendChild(infoTableRow1Col1);
    
    var infoTableRow1Col2 = document.createElement('td');
    infoTableRow1Col2.setAttribute('id', 'stock_entry_' + indexNumber + '_current_price');
    infoTableRow1Col2.setAttribute('class', 'symbol_info_table_col');
    infoTableRow1Col2.innerHTML = _checkAndFormatNumber(data.currentPrice);
    infoTableRow1.appendChild(infoTableRow1Col2);
    
    var infoTableRow1Col3 = document.createElement('td');
    infoTableRow1Col3.setAttribute('id', 'stock_entry_' + indexNumber + '_change_amount');
    infoTableRow1Col3.setAttribute('class', 'symbol_info_table_col');
    infoTableRow1Col3.innerHTML = _checkAndFormatNumber(data.changeAmount);
    infoTableRow1.appendChild(infoTableRow1Col3);
    
    var infoTableRow2 = document.createElement('tr');
    infoTable.appendChild(infoTableRow2);
    
    var infoTableRow2Col1 = document.createElement('td');
    infoTableRow2Col1.setAttribute('class', 'symbol_info_table_col');
    infoTableRow2.appendChild(infoTableRow2Col1);
    
    var updateImg = document.createElement('img');
    updateImg.setAttribute('id', 'stock_entry_' + indexNumber + '_update');
    updateImg.setAttribute('src','images/update.png');
    updateImg.setAttribute('height', '24');
    updateImg.setAttribute('width', '24');
    updateImg.setAttribute('class', 'action_item_picture');    
	updateImg.setAttribute('onclick', 'mwl.toggleClass(\'#progress_anim\', \'progress_visible\');StockTracker.updateDataForStock(' + indexNumber + ');');
    infoTableRow2Col1.appendChild(updateImg);
           
    var infoTableRow2Col2 = document.createElement('td');
    infoTableRow2Col2.setAttribute('class', 'symbol_info_table_col');
    infoTableRow2.appendChild(infoTableRow2Col2);
    
    var removeImg = document.createElement('img');
    removeImg.setAttribute('id', 'stock_entry_' + indexNumber + '_remove');
    removeImg.setAttribute('src', 'images/remove.png');
    removeImg.setAttribute('height', '24');
    removeImg.setAttribute('width', '24');
    removeImg.setAttribute('class', 'action_item_picture');
    removeImg.setAttribute('onclick', 'mwl.toggleClass(\'#progress_anim\', \'progress_visible\');StockTracker.removeStock(' + indexNumber + ');');
    infoTableRow2Col2.appendChild(removeImg);
    
    var infoTableRow2Col3 = document.createElement('td');
    infoTableRow2Col3.setAttribute('class', 'symbol_info_table_col');
    infoTableRow2.appendChild(infoTableRow2Col3);
    
    var extraInfoImg = document.createElement('img');
    extraInfoImg.setAttribute('id', 'stock_entry_' + indexNumber + '_extra_info_button');
    extraInfoImg.setAttribute('src', 'images/more.png');
    extraInfoImg.setAttribute('height', '24');
    extraInfoImg.setAttribute('width', '24');
    extraInfoImg.setAttribute('class', 'action_item_picture');	
    //extraInfoImg.setAttribute('onclick', 'mwl.switchClass(\'#stock_entry_' + indexNumber + '_extra_info\', \'hidden\', \'visible\');');
	extraInfoImg.setAttribute('onclick', 'mwl.toggleClass(\'#stock_entry_' + indexNumber + '_extra_info\', \'visible\');');
    infoTableRow2Col3.appendChild(extraInfoImg);
    
    var extraInfoDiv = document.createElement('div');
    extraInfoDiv.setAttribute('id', 'stock_entry_' + indexNumber + '_extra_info');
    extraInfoDiv.setAttribute('class', 'hidden extra_info_animation');
    entryDiv.appendChild(extraInfoDiv);
    
    var openPriceDiv = document.createElement('div');
    openPriceDiv.setAttribute('id', 'stock_entry_' + indexNumber + '_open_price');
    openPriceDiv.innerHTML = "Open: " + _checkAndFormatNumber(data.open);
    extraInfoDiv.appendChild(openPriceDiv);
    
    var prevCloseDiv = document.createElement('div');
    prevCloseDiv.setAttribute('id', 'stock_entry_' + indexNumber + '_prev_close');
    prevCloseDiv.innerHTML = "Prev Close: " + _checkAndFormatNumber(data.prevClose);
    extraInfoDiv.appendChild(prevCloseDiv);
    
    var dayRangeDiv = document.createElement('div');
    dayRangeDiv.setAttribute('id', 'stock_entry_' + indexNumber + '_day_range');
    dayRangeDiv.innerHTML = "Day Range: " + _checkAndFormatNumber(data.dayLow) + " - " + _checkAndFormatNumber(data.dayHigh);
    extraInfoDiv.appendChild(dayRangeDiv);    
    
    stockSymbols[entryCount] = data.symbol;
    entryCount++;
  }
  
  /**
   * Used to format a number to 2 decimal places. If the value is null then a string of 'No Data' is returned.
   * 
   * @param {Number} value - The number to be formatted
   * @return The formatted number or 'No Data' if the value passed in is null
   */
  function _checkAndFormatNumber(value){
    if (value == null) {
      return 'No Data';
    }
    else {
      return parseFloat(value).toFixed(2);
    }
  }
  
  /**
   * Used to 'repaint' a stock that is already in the results grid. Rather than reconstructing the entire 
   * stock entry just the numbers need to be updated with the most current data.
   * 
   * @param {Object} data -  The dataToSend object from the AjaxWrapper
   */
  function _updatePageElement(data){
    var indexNumber = _getStockIndexNumber(data.symbol);
    
    document.getElementById('stock_entry_' + indexNumber + '_wrapper').setAttribute('class', _setBackgroundImage(data.changeAmount));     
    document.getElementById('stock_entry_' + indexNumber + '_current_price').innerHTML = " " + _checkAndFormatNumber(data.currentPrice);
    document.getElementById('stock_entry_' + indexNumber + '_change_amount').innerHTML = " " + _checkAndFormatNumber(data.changeAmount);
    document.getElementById('stock_entry_' + indexNumber + '_day_range').innerHTML = "Day Range: " + _checkAndFormatNumber(data.dayLow) + " - " + _checkAndFormatNumber(data.dayHigh);
  }
  
  function _updateDataForStock(indexNumber){
    _getData(stockSymbols[indexNumber], true);
  }
  
  function _updateAllStocks() {
    for(var i = 0; i < stockSymbols.length; i++) {
      if (stockSymbols[i] != '' && stockSymbols[i] != undefined) {
        _getData(stockSymbols[i], true);
      }
    }
  }
  
  function _removeStock(indexNumber){
    var stockToRemove = document.getElementById('stock_entry_' + indexNumber + '_wrapper');
    document.getElementById('data_grid').removeChild(stockToRemove);
	mwl.toggleClass('#progress_anim', 'progress_visible');
    
    stockSymbols[indexNumber] = '';
  }
  
  function _collectStocksForPreferences(){
    var prefString = '';
    
    for (var i = 0; i < stockSymbols.length; i++) {
      if (stockSymbols[i] != '' && stockSymbols[i] != undefined) {
        prefString += stockSymbols[i] + ' ';
      }
    }
    
    return prefString;
  }
  
  return {
    init: _init,
    getData: _getData,
    removeStock: _removeStock,
    updateDataForStock: _updateDataForStock,
    loadStocksFromPrefs: _loadStocksFromPrefs,
    updateAllStocks: _updateAllStocks
  }
  
}());
